package com.zycoin.pagehelp.mybatis.plugins;

import com.zycoin.pagehelp.mybatis.Dialect;
import com.zycoin.pagehelp.mybatis.Page;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.util.Properties;

/**
 * mybatis分页插件
 * 注意：dialect必须配置，为且dialect+"Dialect"为方言类名
 * 暂时只适配Sybase
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class,Integer.class})})
public class PaginationStatementHandlerInterceptor implements Interceptor {

    private final static Logger logger = LoggerFactory.getLogger(PaginationStatementHandlerInterceptor.class);

    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_REFLECTOR_FACOTRY = new DefaultReflectorFactory();

    private Dialect dialect;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if(null == dialect)
            return invocation.proceed();
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY,DEFAULT_REFLECTOR_FACOTRY);
        RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");
        // 没有分页参数
        if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
            return invocation.proceed();
        }

        BoundSql boundSql = statementHandler.getBoundSql();
        String originalSql = boundSql.getSql();
        // 获取总记录数
        Page<?> page = (Page<?>) rowBounds;
        Connection connection = (Connection) invocation.getArgs()[0];
        /*获取查询总条数sql*/
        String countSql = dialect.getCountSql(originalSql);
        /*查询总条数*/
        dialect.getTotal(statementHandler, connection, countSql, page);
        /*获取分页查询sql*/
        String pageSql = dialect.getPageSql(page, originalSql);
        /*处理分页查询数据*/
        dialect.processPageInfo(metaStatementHandler, pageSql, page);

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        String packageName = this.getClass().getPackage().getName();
        packageName = packageName.substring(0, packageName.lastIndexOf(".")) + ".dialect.";
        String dialectClasss = properties.getProperty("dialect");
        try {
            Class<?> aClass = Class.forName(packageName + dialectClasss + "Dialect");
            dialect = (Dialect) aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("数据分页【{}】方言为找到", dialectClasss, e);
        }
    }
}
